Scala面向对象

Posted by Jackson on 2017-10-13

spark源码:https://github.com/apache/spark/archive/v2.2.2.zip

scala的构造器、主构造器和附属构造器

主构造器用clclass定义,附属构造器用def定义名称为this(),
在附属构造器的第一行必须调用主构造器和其他附属构造器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* scala 中的构造器
*/
// 主构造器
class ContructTest(name: String, age: Int) {
val famila: String = "hello"
val height: Int = 10

def this(name: String) {
this(name, 12)
}

// 辅助构造器第一行必须调用主构造器或者其他附属构造器
def this(name: String, age: Int, salary: Int) {
this(name)
}

def eat(): String = {
" eat breakfast"
}
}

抽象类和抽象方法

在抽象类中定义的方法如果没有方法体,那么在子类中必须重写该方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
abstract class Animal {
val color: String
def eat()
def run()={
println("hello")
}
}

class Bord extends Animal {
override val color: String = ""
override def eat(): Unit = {
println("eat")
}
}

半生类和半生对象,当class定义的类名和object定义的名称相同的时候,class定义的叫做objec 对象的伴生类,object定义的叫做class的陪伴生对象。
一般在object里面定义一个apply方法,该方法通常的作用是new 一个类对象。如何判断是class的apply还是object的apply方法?
class的对象在spark的源码中调用apply方法的时候对象都是小写的
object一般都是大写的,用大写的object名称调用apply方法,即大写开头调object 小写开头调class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Student(name: String, age: Int) {
val money = 200

def write() = {
println("student write homework")
}
}

object Student {
val project: String = "math"

def study() = {
println("student study")
}

def apply(name: String, age: Int): Student = new Student(name, age)
}

样例类

样例类 用case class 来修定义样例类,可以当做静态来理解,用Dog()这种方式使用
与object 不同的是object 调用的时候直接是名称Dog.xxx 而caseclass则是Dog().xxx
特点是不用new可以直接使用,并且在spark sql中使用的比较多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
object CaseClassApp {
def main(args: Array[String]): Unit = {
Dog("Tom").eat()
println(Cat().age)
Cat().eat()
}
}
case class Cat() {
val age: Int = 39
def eat() = {
println("Cat eat fish")
}
}

case class Dog(name: String) {
val aa = "hh"
def eat(): Unit = {
println(name + " eat chicken")
}
}

Trait

实现Trait和abstract的时候都用extends 当有多个的时候第一个用extends,后面的用with

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
object TraitApp {
def main(args: Array[String]): Unit = {
val controller = new AnimalController()
controller.eat()
controller.run()
controller.serviec()
}
}
class AnimalController extends Dog with AnimalService with Animal {
override def run(): Unit = {
println("run")
}
override def serviec(): Unit = {
println("service")
}
override def eat(): Unit = {
println("eat")
}
}
trait Animal {
def eat()
}
trait AnimalService {
def serviec()
}
abstract class Dog() {
def run()
}

scala中的数组Array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
第一种方式定义数组 
val array = new Array[Int](10)
for (arr <- array) {
println(arr)
}

第二种方式定义数组
val arr1 = Array("hello","spark","hive","hbase")
for (arr <-arr1){
println(arr)
}
// 变长数组定义
val arrbuff = ArrayBuffer[String]()
// 添加元素
arrbuff.append("hello")
arrbuff.append("spark")
arrbuff.append("scala")

// 获取元素
println(arrbuff(0))
for (arr <- arrbuff) {
println(arr)
}
// 修改元素
arrbuff(0) = "hadoop"

// 删除元素
arrbuff.remove(0)
// 获取长度
arrbuff.length

变长数组(声明泛型)

1
2
3
4
5
6
7
8
9
10
11
12
val arr2 = ArrayBuffer[Int]() 

变长数组的分析
1) ArrayBuffer 是变长数组,类似 java 的 ArrayList
2) val arr2 = ArrayBuffer[Int]() 也是使用的 apply 方法构建对象
3) def append(elems: A*) { appendAll(elems) } 接收的是可变参数.
4) 每append一次,arr在底层会重新分配空间,进行扩容,arr2的内存地址会发生变化,也就成为新的ArrayBuffer

定长数组与变长数组的转换

1) arr1.toBuffer //定长数组转可变数组
2) arr2.toArray //可变数组转定长数组

Scala中的List

Scala 中的 List 和 Java List 不一样,在 Java 中 List 是一个接口,真正存放数据是 ArrayList,而 Scala 的 List
可以直接存放数据,就是一个 object,默认情况下 Scala 的 List 是不可变的,List 属于序列 Seq。

创建List
val list1 = List(1, 2, 3)

  1. List 默认为不可变的集合
  2. List 在 scala 包对象声明的,因此不需要引入其它包也可以使用
  3. val List = scala.collection.immutable.List
  4. List 中可以放任何数据类型,比如 arr1 的类型为 List[Any]
  5. 如果希望得到一个空列表,可以使用 Nil 对象, 在 scala 包对象声明的,因此不需要引入其它包也可以使用

向列表中增加元素, 会返回新的列表/集合对象。注意:Scala 中 List 元素的追加形式非常独特,和 Java 不一样。

List的语法糖操作如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
val list1 = List(1, 2, 3)
val list3 = List("hello|Spark", "word|Wall", "New|Year")

// + 进行的是字符串的拼接
val list4 = list3 + "hadoop"
//(hello|Spark, word,Wall, New|Year)hadoop

// +: 是在list的头部进行的拼接
val list5 = list3 +:("hadoop")
// List(hadoop, hello|Spark, word,Wall, New|Year)

// val list6 = "hadoop" :+ list3
// Vector(h, a, d, o, o, p, List(hello|Spark, word,Wall, New|Year))

// :: 是将前面的List作为一个整体拼接到后面的List上面
val list7 = list1 :: list3
// List(List(1, 2, 3), hello|Spark, word|Wall, New|Year)

// zip() 是将两个List中的元素每个元素对应位置形成一个键值对
val list8 = list1.zip(list3)
// List((1,hello|Spark), (2,word,Wall), (3,New|Year))

// ::: 是将两个List中的元素进行拼接形成一个新的List
val list9 = list1.:::(List("Flink", "Flink2"))
// LList(Flink, Flink2, 1, 2, 3)

// flatMap是将一个值映射成为多个值
val list10 = list3.flatMap(x => x.split(","))
// List(hello, Spark, word, Wall, New, Year)

// ++ 是将后面List中的每一项拼接到前面List中
val list11 = list3.++(List("Shell", "Kafka"))
// List(hello|Spark, word,Wall, New|Year, Shell, Kafka)

// 对List中的每一个值进行处理,返回处理后的结果
val list12 = list1.map(x => x + 1)
// List(2, 3, 4)

// 对List中的每一个值作用上传入的函数
list1.foreach(println(_))

// List 内容的反转
val list14 = list1.reverse
// List(3, 2, 1)

ListBuffer

// ListBuffer 的创建
val buffer = ListBufferString
// 添加单个元素
buffer.append(“Hadoop”)
buffer.append(“HDFS”)

// 在指定位置添加元素
buffer.insert(0,“Shell”)

// 在指定位置添加一个List
buffer.insertAll(0,List(“Kafka”,“Hive”))

// 删除指定位置的元素
buffer.remove(0)

// 更新指定位置的元素
buffer.update(0,“HIVE”)

// 获取buffer的头部
println(buffer.head)

// 获取buffer的尾部
println(buffer.tail)

// 获取buffer的大小
println(buffer.length)
println(buffer.size)

// 清空buffer
buffer.clear()